//给你二叉树的根结点 root ，请你将它展开为一个单链表： 
//
// 
// 展开后的单链表应该同样使用 TreeNode ，其中 right 子指针指向链表中下一个结点，而左子指针始终为 null 。 
// 展开后的单链表应该与二叉树 先序遍历 顺序相同。 
// 
//
// 
//
// 示例 1： 
//
// 
//输入：root = [1,2,5,3,4,null,6]
//输出：[1,null,2,null,3,null,4,null,5,null,6]
// 
//
// 示例 2： 
//
// 
//输入：root = []
//输出：[]
// 
//
// 示例 3： 
//
// 
//输入：root = [0]
//输出：[0]
// 
//
// 
//
// 提示： 
//
// 
// 树中结点数在范围 [0, 2000] 内 
// -100 <= Node.val <= 100 
// 
//
// 
//
// 进阶：你可以使用原地算法（O(1) 额外空间）展开这棵树吗？ 
// Related Topics 栈 树 深度优先搜索 链表 二叉树 👍 1224 👎 0

package leetcode.editor.cn;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

class FlattenBinaryTreeToLinkedList {
    public static void main(String[] args) {
        Solution solution = new FlattenBinaryTreeToLinkedList().new Solution();
    }
    //leetcode submit region begin(Prohibit modification and deletion)

    public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode() {
        }

        TreeNode(int val) {
            this.val = val;
        }

        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }

    class Solution {

        // 前序递归遍历，空间复杂度贺时间复杂度都为O(n)
        /*List<TreeNode> list = new ArrayList<>();

        public void flatten(TreeNode root) {
            if (root == null) return;
            traversal(root);
            for (int i = 1; i < list.size(); i++) {
                TreeNode pre = list.get(i - 1), cur = list.get(i);
                pre.right = cur;
                pre.left = null;
                pre = cur;
            }
        }

        public void traversal(TreeNode root) {
            if (root == null) return;
            list.add(root);
            traversal(root.left);
            traversal(root.right);
        }*/


        // 迭代遍历，在遍历的时候直接进行拼接，因为节点存储在栈中，所以不会丢失左右节点
        // 空间复杂度贺时间复杂度都为O(n)，申请了栈
        /*public void flatten(TreeNode root) {
            if (root == null) return;
            Stack<TreeNode> stack = new Stack<>();
            stack.push(root);
            TreeNode pre = null;
            while (!stack.isEmpty()) {
                TreeNode cur = stack.pop();
                if (pre != null) {
                    pre.left = null;
                    pre.right = cur;
                }

                // 移动pre
                pre = cur;

                if (cur.right != null) stack.push(cur.right);
                if (cur.left != null) stack.push(cur.left);
            }
        }*/

        // 时间复杂度O(n)，空间复杂度O(1)
        /*public void flatten(TreeNode root) {
            TreeNode cur = root;
            while (cur != null) {
                if (cur.left != null) {
                    TreeNode next = cur.left;
                    TreeNode predecessor = next;
                    // 找到左子树前序遍历的最后一个节点
                    while (predecessor.right != null) {
                        predecessor = predecessor.right;
                    }
                    // 拼接
                    predecessor.right =cur.right;
                    cur.left = null;
                    cur.right = next;
                }
                cur = cur.right;
            }
        }*/

        // 后序遍历
        public void flatten(TreeNode root) {
            if (root == null) {
                return;
            }

            flatten(root.left);
            flatten(root.right);

            // 保存下左右节点
            TreeNode left = root.left;
            TreeNode right = root.right;

            // 左节点置为null
            root.left = null;
            // 右节点放左节点
            root.right = left;

            TreeNode p = root;
            // 找到最后一个节点
            while (p.right != null) {
                p = p.right;
            }

            // 拼接原来的右节点
            p.right = right;

        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}
